﻿using System.Windows.Data;
using System.Windows;
using System;
using WpfHero;

namespace Tutorial
{
    /// <summary>
    /// Converts a Boolean value to FontWeight.
    /// </summary>
    public class BooleanToBoldConverter : IValueConverter
    {
        /// <summary>
        /// Converts from Boolean to FontWeight.
        /// </summary>
        /// <param name="value">The value to convert.</param>
        /// <param name="targetType">The target type.</param>
        /// <param name="parameter">Converter parameter.</param>
        /// <param name="culture">Culture for conversion.</param>
        /// <returns>The converted value.</returns>
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            // This is a really simple conversion. If the source value is true, we return FontWeights.Bold. Otherwise FontWeights.Normal.
            return (bool)value ? FontWeights.Bold : FontWeights.Normal;
        }

        /// <summary>
        /// Converts from FontWeight to Boolean.
        /// </summary>
        /// <param name="value">The value to convert.</param>
        /// <param name="targetType">The target type.</param>
        /// <param name="parameter">Converter parameter.</param>
        /// <param name="culture">Culture for conversion.</param>
        /// <returns>The converted value.</returns>
        /// <remarks>This function is not implemented and not used by the tutorial.</remarks>
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts the length of a note to a width value for the gem models.
    /// </summary>
    public class GemSizeConverter : IValueConverter
    {
        /// <summary>
        /// The conversion ratio between note length and screen width.
        /// </summary>
        public const double MillisecondsPerPixel = 10;

        /// <summary>
        /// Converts a note to a Width value.
        /// </summary>
        /// <param name="value">The value to convert.</param>
        /// <param name="targetType">The target type.</param>
        /// <param name="parameter">Converter parameter.</param>
        /// <param name="culture">Culture for conversion.</param>
        /// <returns>The converted value.</returns>
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            // We skip conversion if there is nothing to convert
            if (value == null)
                return null;

            // If for some reason we received something other than GemModel, throw an exception
            GemModel val = value as GemModel;
            if (val == null)
                throw new ArgumentException();

            // Return the ammount of pixels based on the conversion ratio.
            double result = (val.EndAt.Value - val.StartAt).TotalMilliseconds / MillisecondsPerPixel;
            return result;
        }

        /// <summary>
        /// Reverse conversion
        /// </summary>
        /// <param name="value">The value to convert.</param>
        /// <param name="targetType">The target type.</param>
        /// <param name="parameter">Converter parameter.</param>
        /// <param name="culture">Culture for conversion.</param>
        /// <returns>The converted value.</returns>
        /// <remarks>This function is not implemented and not used by the tutorial.</remarks>
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts the position of a note in the song to a Thickness (margin) value.
    /// </summary>
    public class GemPauseConverter : IValueConverter
    {
        /// <summary>
        /// Converts a note to a Thickness (margin) value.
        /// </summary>
        /// <param name="value">The value to convert.</param>
        /// <param name="targetType">The target type.</param>
        /// <param name="parameter">Converter parameter.</param>
        /// <param name="culture">Culture for conversion.</param>
        /// <returns>The converted value.</returns>
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            // We skip conversion if there is nothing to convert
            if (value == null)
                return null;

            // If for some reason we received something other than GemModel, throw an exception
            GemModel val = value as GemModel;
            if (val == null)
                throw new ArgumentException();

            // Calculate the distance from the beginning of the song, or from the previous note.
            TimeSpan ts = val.StartAt;
            if (val.Previous != null)
                ts -= val.Previous.EndAt.Value;

            // Return a margin matching the distance between the note and the beginning of the song or the previous note.
            // The calculation uses the same ratio as the GemSizeConverter.
            return new Thickness(ts.TotalMilliseconds / GemSizeConverter.MillisecondsPerPixel, 0, 0, 0);
        }

        /// <summary>
        /// Reverse conversion.
        /// </summary>
        /// <param name="value">The value to convert.</param>
        /// <param name="targetType">The target type.</param>
        /// <param name="parameter">Converter parameter.</param>
        /// <param name="culture">Culture for conversion.</param>
        /// <returns>The converted value.</returns>
        /// <remarks>This function is not implemented and not used by the tutorial.</remarks>
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}